// ============================================================================
// IPC 客户端 - 类型安全的IPC通信
// ============================================================================

import { IPCEvents, IPCResponse, IPCEventListeners } from '../types'

/**
 * 类型安全的IPC客户端
 * 提供强类型的IPC通信接口
 */
export class IPCClient {
  private ipcRenderer: any

  constructor() {
    // 在渲染进程中，通过预加载脚本获取IPC接口
    this.ipcRenderer = (window as any).electronAPI
    
    if (!this.ipcRenderer) {
      throw new Error('IPC renderer not available. Make sure preload script is loaded.')
    }
  }

  /**
   * 调用IPC方法
   */
  async invoke<K extends keyof IPCEvents>(
    channel: K,
    ...args: Parameters<IPCEvents[K]>
  ): Promise<Awaited<ReturnType<IPCEvents[K]>>> {
    try {
      const response = await this.ipcRenderer.invoke(channel, ...args) as IPCResponse
      
      if (!response.success) {
        throw new Error(response.error?.message || 'IPC call failed')
      }
      
      return response.data
    } catch (error) {
      console.error(`IPC call failed: ${channel}`, error)
      throw error
    }
  }

  /**
   * 监听IPC事件
   */
  on<K extends keyof IPCEventListeners>(
    channel: K,
    listener: IPCEventListeners[K]
  ): void {
    if (this.ipcRenderer.on) {
      this.ipcRenderer.on(channel, listener)
    }
  }

  /**
   * 移除IPC事件监听器
   */
  off<K extends keyof IPCEventListeners>(
    channel: K,
    listener: IPCEventListeners[K]
  ): void {
    if (this.ipcRenderer.off) {
      this.ipcRenderer.off(channel, listener)
    }
  }

  /**
   * 一次性监听IPC事件
   */
  once<K extends keyof IPCEventListeners>(
    channel: K,
    listener: IPCEventListeners[K]
  ): void {
    if (this.ipcRenderer.once) {
      this.ipcRenderer.once(channel, listener)
    }
  }

  /**
   * 移除所有监听器
   */
  removeAllListeners(channel?: keyof IPCEventListeners): void {
    if (this.ipcRenderer.removeAllListeners) {
      this.ipcRenderer.removeAllListeners(channel)
    }
  }
}

/**
 * 全局IPC客户端实例
 */
export const ipcClient = new IPCClient()

/**
 * IPC调用的便捷方法
 */
export const ipc = {
  // 登录相关
  login: {
    start: () => ipcClient.invoke('login:start'),
    validate: (accountId: string) => ipcClient.invoke('login:validate', accountId),
    getAccounts: () => ipcClient.invoke('login:get-accounts'),
    deleteAccount: (accountId: string) => ipcClient.invoke('login:delete-account', accountId),
    deleteInvalidAccounts: () => ipcClient.invoke('login:delete-invalid-accounts')
  },

  // 任务相关
  task: {
    create: (task: any) => ipcClient.invoke('task:create', task),
    start: (taskId: string) => ipcClient.invoke('task:start', taskId),
    stop: (taskId: string) => ipcClient.invoke('task:stop', taskId),
    delete: (taskId: string) => ipcClient.invoke('task:delete', taskId),
    getAll: () => ipcClient.invoke('task:get-all'),
    getById: (taskId: string) => ipcClient.invoke('task:get-by-id', taskId),
    getLogs: (taskId: string) => ipcClient.invoke('task:get-logs', taskId)
  },

  // 配置相关
  config: {
    get: () => ipcClient.invoke('config:get'),
    update: (config: any) => ipcClient.invoke('config:update', config),
    reset: () => ipcClient.invoke('config:reset')
  },

  // 数据相关
  data: {
    export: (taskId: string, format: any) => ipcClient.invoke('data:export', taskId, format),
    getStats: () => ipcClient.invoke('data:get-stats'),
    getWeiboData: (taskId: string, page?: number, pageSize?: number) => 
      ipcClient.invoke('data:get-weibo-data', taskId, page, pageSize),
    searchWeibo: (query: string, filters?: any) => 
      ipcClient.invoke('data:search-weibo', query, filters),
    deleteTaskData: (taskId: string) => ipcClient.invoke('data:delete-task-data', taskId)
  },

  // 系统相关
  system: {
    getInfo: () => ipcClient.invoke('system:get-info'),
    openExternal: (url: string) => ipcClient.invoke('system:open-external', url),
    showItemInFolder: (path: string) => ipcClient.invoke('system:show-item-in-folder', path)
  }
}

/**
 * IPC事件监听的便捷方法
 */
export const ipcEvents = {
  // 任务事件
  onTaskProgress: (callback: (taskId: string, progress: any) => void) => {
    ipcClient.on('task:progress-update', callback)
  },
  
  onTaskLog: (callback: (taskId: string, log: any) => void) => {
    ipcClient.on('task:log-update', callback)
  },
  
  onTaskStatusChange: (callback: (taskId: string, status: any) => void) => {
    ipcClient.on('task:status-change', callback)
  },

  // 通知事件
  onNotification: (callback: (notification: any) => void) => {
    ipcClient.on('notification:show', callback)
  },

  // 配置事件
  onConfigChanged: (callback: (config: any) => void) => {
    ipcClient.on('config:changed', callback)
  },

  // 移除监听器
  off: (channel: keyof IPCEventListeners, callback: any) => {
    ipcClient.off(channel, callback)
  }
}

/**
 * IPC错误处理装饰器
 */
export function withErrorHandling<T extends (...args: any[]) => Promise<any>>(
  fn: T,
  errorHandler?: (error: Error) => void
): T {
  return (async (...args: any[]) => {
    try {
      return await fn(...args)
    } catch (error) {
      if (errorHandler) {
        errorHandler(error as Error)
      } else {
        console.error('IPC call failed:', error)
      }
      throw error
    }
  }) as T
}

/**
 * IPC重试装饰器
 */
export function withRetry<T extends (...args: any[]) => Promise<any>>(
  fn: T,
  maxRetries: number = 3,
  delay: number = 1000
): T {
  return (async (...args: any[]) => {
    let lastError: Error
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await fn(...args)
      } catch (error) {
        lastError = error as Error
        
        if (attempt < maxRetries) {
          await new Promise(resolve => setTimeout(resolve, delay * attempt))
        }
      }
    }
    
    throw lastError!
  }) as T
}

/**
 * IPC超时装饰器
 */
export function withTimeout<T extends (...args: any[]) => Promise<any>>(
  fn: T,
  timeoutMs: number = 30000
): T {
  return (async (...args: any[]) => {
    return Promise.race([
      fn(...args),
      new Promise<never>((_, reject) => {
        setTimeout(() => {
          reject(new Error(`IPC call timed out after ${timeoutMs}ms`))
        }, timeoutMs)
      })
    ])
  }) as T
}
